/*
 * FileName: observer.cc
 * Author: 李波(Edwin Lee)
 * Date: 2024-07-17 15:04:12
 * Version: 1.0
 * Description: 定义： 定义对象间的一种一对多的依赖关系，当一个对象的状态发生改变时，所有依赖于它的对象都得到通知并被自动更新。

主要解决：一个对象状态改变给其他对象通知的问题，而且要考虑到易用和低耦合，保证高度的协作。

何时使用：一个对象（目标对象）的状态发生改变，所有的依赖对象（观察者对象）都将得到通知，进行广播通知。
 */
#include <iostream>
#include <unordered_map>
#include <list>
using namespace std;

//观察者抽象类
class Observer
{
public:
	//处理消息的接口
	virtual void handle(int msgid) = 0;
};

// 第一个观察者
class Observer1:public Observer
{
public:
	void handle(int msgid)
	{
		switch(msgid)
		{
			case 1:
				cout<<"Observer1 recv 1 msg!"<<endl;
				break;
			case 2:
				cout<<"Observer1 recv 2 msg!"<<endl;
				break;
			default:
				cout<<"Observer1 recv unknow msg!"<<endl;
				break;
		}
	}
};

// 第二个观察者
class Observer2:public Observer
{
public:
	void handle(int msgid)
	{
		switch(msgid)
		{
			case 2:
				cout<<"Observer2 recv 2 msg!"<<endl;
				break;
			default:
				cout<<"Observer2 recv unknow msg!"<<endl;
				break;
		}
	}
};

class Observer3:public Observer
{
public:
	void handle(int msgid)
	{
		switch(msgid)
		{
			case 1:
				cout<<"Observer3 recv 1 msg!"<<endl;
				break;
			case 2:
				cout<<"Observer3 recv 2 msg!"<<endl;
				break;
			default:
				cout<<"Observer3 recv unknow msg!"<<endl;
				break;
		}
	}
};

//主题类
class Subject
{
public:
	//给主题添加观察者对象
	void addObserver(Observer* obser, int msgid)
	{
		subMap_[msgid].push_back(obser);
		/*
		auto it = subMap_.find(msgid);
		if(it != subMap_.end())
		{
			it->second.push_back(obser);
		}
		else 
		{
			list<Observer*> lis;
			lis.push_back(obser);
			subMap_.insert({msgid,lis});
		}
		*/
	}

	//主题检查发生改变，通知相应的观察者对象处理事件
	void dispatch(int msgid)
	{
		auto it = subMap_.find(msgid);
		if(it != subMap_.end())
		{
			for(Observer* pObser:it->second)
			{
				pObser->handle(msgid);
			}
		}
	}
private:
	unordered_map<int, list<Observer*>> subMap_;
};

int main()
{
	Subject subject;
	Observer* p1 = new Observer1();
	Observer* p2 = new Observer2();
	Observer* p3 = new Observer3();

	subject.addObserver(p1,1);
	subject.addObserver(p1,2);
	subject.addObserver(p2,2);
	subject.addObserver(p3,1);
	subject.addObserver(p3,3);

	int msgid = 0;
	for(;;)
	{
		cout<<"输入消息id:";
		cin>>msgid;
		if(msgid == -1)
			break;
		subject.dispatch(msgid);
	}
	return 0;
}
